package com.kyzh.core.uis;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.DrawableRes;
import androidx.core.content.ContextCompat;

import com.kyzh.core.R;

public class SimpleRatingBar extends View {

    /** 默认的星星图标 */
    private Drawable mNormalDrawable;
    /** 选中的星星图标 */
    private Drawable mSelectDrawable;

    /** 当前星等级 */
    private int mCurrentGrade;
    /** 星星总数量 */
    private int mGradeCount;
    /** 星星之间的间隔 */
    private int mGradeSpace;
    /** 星星的宽度 */
    private int mGradeWidth;
    /** 星星的高度 */
    private int mGradeHeight;

    /** 星星变化监听事件 */
    private OnRatingChangeListener mListener;

    /** 星星位置记录 */
    private final Rect mGradeBounds = new Rect();

    public SimpleRatingBar(Context context) {
        this(context, null);
    }

    public SimpleRatingBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SimpleRatingBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SimpleRatingBar);

        mNormalDrawable = ContextCompat.getDrawable(getContext(), array.getResourceId(R.styleable.SimpleRatingBar_normalDrawable, R.drawable.rating_star_off_ic));
        mSelectDrawable = ContextCompat.getDrawable(getContext(), array.getResourceId(R.styleable.SimpleRatingBar_selectDrawable, R.drawable.rating_star_on_ic));
        // 两张图片的宽高不一致
        if (mNormalDrawable.getIntrinsicWidth() != mSelectDrawable.getIntrinsicWidth() || mNormalDrawable.getIntrinsicHeight() != mSelectDrawable.getIntrinsicHeight()) {
            throw new IllegalStateException("The width and height of the picture do not agree");
        }

        mCurrentGrade = array.getInt(R.styleable.SimpleRatingBar_grade, 0);
        mGradeCount = array.getInt(R.styleable.SimpleRatingBar_gradeCount, 5);
        mGradeWidth = array.getDimensionPixelSize(R.styleable.SimpleRatingBar_gradeWidth, mNormalDrawable.getIntrinsicWidth());
        mGradeHeight = array.getDimensionPixelSize(R.styleable.SimpleRatingBar_gradeHeight, mSelectDrawable.getIntrinsicHeight());
        mGradeSpace = (int) array.getDimension(R.styleable.SimpleRatingBar_gradeSpace, mGradeWidth / 4f);

        array.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int measuredWidth = (mGradeWidth * mGradeCount) + (mGradeSpace * (mGradeCount + 1));
        int measuredHeight = mGradeHeight;

        setMeasuredDimension(measuredWidth + getPaddingLeft() + getPaddingRight(),
                measuredHeight + getPaddingTop() + getPaddingBottom());
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 如果控件处于不可用状态，直接不处理
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                int grade = 0;
                int distance = (int) (event.getX() - getPaddingLeft() - mGradeSpace);
                if (distance > 0) {
                    grade = distance / (mGradeWidth + mGradeSpace) + 1;
                }

                grade = Math.min(Math.max(grade, 0), mGradeCount);

                if (grade != mCurrentGrade) {
                    mCurrentGrade = grade;
                    invalidate();
                    if (mListener != null) {
                        mListener.onRatingChanged(this, mCurrentGrade, true);
                    }
                }
                break;
            default:
                break;
        }

        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < mGradeCount; i++) {

            int start = mGradeSpace + (mGradeWidth + mGradeSpace) * i;

            mGradeBounds.left = getPaddingLeft() + start;
            mGradeBounds.top = getPaddingTop();
            mGradeBounds.right = mGradeBounds.left + mGradeWidth;
            mGradeBounds.bottom = mGradeBounds.top + mGradeHeight;

            if (mCurrentGrade > i) {
                mSelectDrawable.setBounds(mGradeBounds);
                mSelectDrawable.draw(canvas);
            } else {
                mNormalDrawable.setBounds(mGradeBounds);
                mNormalDrawable.draw(canvas);
            }
        }
    }

    public void setRatingDrawable(@DrawableRes int normalDrawableId, @DrawableRes int selectDrawableId) {
        setRatingDrawable(ContextCompat.getDrawable(getContext(), normalDrawableId), ContextCompat.getDrawable(getContext(), selectDrawableId));
    }

    public void setRatingDrawable(Drawable normalDrawable, Drawable selectDrawable) {
        if (normalDrawable == null || selectDrawable == null) {
            throw new IllegalStateException("Drawable cannot be empty");
        }

        // 两张图片的宽高不一致
        if (normalDrawable.getIntrinsicWidth() != selectDrawable.getIntrinsicWidth() || normalDrawable.getIntrinsicHeight() != selectDrawable.getIntrinsicHeight()) {
            throw new IllegalStateException("The width and height of the picture do not agree");
        }

        mNormalDrawable = normalDrawable;
        mSelectDrawable = selectDrawable;
        mGradeWidth = mNormalDrawable.getIntrinsicWidth();
        mGradeHeight = mNormalDrawable.getIntrinsicHeight();
        requestLayout();
    }

    public int getGrade() {
        return mCurrentGrade;
    }

    public void setGrade(int grade) {
        if (grade > mGradeCount) {
            return;
        }
        mCurrentGrade = grade;
        invalidate();
        if (mListener != null) {
            mListener.onRatingChanged(this, mCurrentGrade, false);
        }
    }

    public int getGradeCount() {
        return mGradeCount;
    }

    public void setGradeCount(int count) {
        if (count > mCurrentGrade) {
            mCurrentGrade = count;
        }
        mGradeCount = count;
        invalidate();
    }

    public void setGradeSpace(int space) {
        mGradeSpace = space;
        requestLayout();
    }

    public void setOnRatingBarChangeListener(OnRatingChangeListener listener) {
        mListener = listener;
    }

    public interface OnRatingChangeListener {

        /**
         * 评分发生变化监听时回调
         *
         * @param grade             当前星星数
         * @param touch             是否通过触摸改变
         */
        void onRatingChanged(SimpleRatingBar ratingBar, int grade, boolean touch);
    }
}